/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit;

import static com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil.getBodies;

import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.uml2.uml.InteractionConstraint;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.ValueSpecification;

import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.diagram.sequence.sedi.edit.manager.GuardEditManager;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.DeletionEditPolicy;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.GuardDirectEditPolicy;
import com.cea.papyrus.diagram.sequence.sedi.figures.GuardFigure;
import com.cea.papyrus.diagram.sequence.sedi.figures.ILabeledFigure;
import com.cea.papyrus.diagram.sequence.sedi.figures.InteractionFragmentFigure1;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Edit part for Interaction Constraints (ICs guard individual Interaction Operands in
 * Combined Fragments).
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class GuardEditPart extends SeDiSubpartEditPart<InteractionConstraint> {

    public GuardEditPart(GraphElement view, ModelManager modelManager) {
        super(view, modelManager);
    }

    @Override
    protected IFigure createFigure() {
        return new GuardFigure();
    }

    @Override
    protected void createEditPolicies() {
        super.createEditPolicies();

        // override the default NamedElement policy with a specialized policy
        installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new GuardDirectEditPolicy());

        // Add edit policy to handle deletion requests (replace SeDiSubpartEditPolicy)
		installEditPolicy(
				EditPolicy.COMPONENT_ROLE,
		        new DeletionEditPolicy());
    }

    // --- Direct edit ---

    @Override
    protected void performDirectEdit(final Request request) {
        new GuardEditManager(this, getCellEditorLocator()).show();
    }

    @Override
    public boolean understandsRequest(Request req) {
        // Extra condition for state invariants: we only allow direct editing
        // when we understand the data structure. We require the StateInvariant
        // to have an invariant Constraint with a Specification of type
        // OpaqueExpression. It is the Body value of the OpaqueExpression
        // that is edited.
        if (RequestConstants.REQ_DIRECT_EDIT.equals(req.getType())) {
            ValueSpecification s = getUmlElement().getSpecification();
            return (s != null && s instanceof OpaqueExpression);
        } else
            return super.understandsRequest(req);
    }

    // --- Synchronization ---

    @SuppressWarnings("unchecked")
    protected void refreshVisualsBounds() {
        GraphNode model = (GraphNode) getModel();
        InteractionFragmentFigure1 figure = (InteractionFragmentFigure1) getFigure();

        final Rectangle bounds = new Rectangle(model.getPosition(), model.getSize());
        final Rectangle preferred = figure.getPreferredFigureBounds(bounds, bounds);

        if (getParent() != null) // may be null: when the EP is removed
            ((GraphicalEditPart) getParent()).setLayoutConstraint(this, figure, preferred);
        figure.setBounds(preferred);
    }

    @Override
    protected void refreshVisualsLabel() {
        String label = "<Unsupported expression>";
        InteractionConstraint guard = getUmlElement();
        ValueSpecification spec = guard.getSpecification();
        if (spec instanceof OpaqueExpression) {
            List<String> bodies = getBodies((OpaqueExpression) spec);
            if (!bodies.isEmpty())
                label = bodies.get(0);
        } else {
            label = spec.stringValue();
        }
        ILabeledFigure figure = (ILabeledFigure) getFigure();
        figure.setLabel(label != null ? label : "");
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void umlModelChanged(Notification evt) {
        switch (evt.getFeatureID(UMLPackage.class)) {
        case UMLPackage.NAMED_ELEMENT:
            // ignore
            break;

        case UMLPackage.INTERACTION_CONSTRAINT__SPECIFICATION:
            // =case UMLPackage.OPAQUE_EXPRESSION__BODY:
            if (evt.getOldValue() != null && evt.getOldValue() instanceof EObject)
                ((EObject) evt.getOldValue()).eAdapters().remove(umlAdapter);
            if (evt.getNewValue() != null && evt.getNewValue() instanceof EObject)
                ((EObject) evt.getNewValue()).eAdapters().add(umlAdapter);
            refreshVisuals();
            break;

        // case UMLPackage.OPAQUE_EXPRESSION__BODY:
        // refreshVisuals();
        // break;

        default:
            super.umlModelChanged(evt);
        }
    }

    // --- Activation ---

    @SuppressWarnings("unchecked")
    @Override
    public void activate() {
        if (!isActive()) {
            super.activate();

            ValueSpecification valueSpec = getUmlElement().getSpecification();
            if (valueSpec != null)
                valueSpec.eAdapters().add(umlAdapter);
        }
    }

    @Override
    public void deactivate() {
        if (isActive()) {
            ValueSpecification valueSpec = getUmlElement().getSpecification();
            if (valueSpec != null)
                valueSpec.eAdapters().remove(umlAdapter);

            super.deactivate();
        }
    }

}
